home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / dbg / ds3100.md / dbgMain.c < prev    next >
C/C++ Source or Header  |  1992-12-18  |  32KB  |  1,248 lines

  1. /* dbgMain.c -
  2.  *
  3.  *    This contains the routines which read and execute commands from kdbx.
  4.  *
  5.  *    Copyright (C) 1989 Digital Equipment Corporation.
  6.  *    Permission to use, copy, modify, and distribute this software and
  7.  *    its documentation for any purpose and without fee is hereby granted,
  8.  *    provided that the above copyright notice appears in all copies.  
  9.  *    Digital Equipment Corporation makes no representations about the
  10.  *    suitability of this software for any purpose.  It is provided "as is"
  11.  *    without express or implied warranty.
  12.  */
  13.  
  14. #ifndef lint
  15. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/dbg/ds3100.md/dbgMain.c,v 9.13 92/09/29 15:52:12 jhh Exp $ SPRITE (Berkeley)";
  16. #endif not lint
  17.  
  18. #include <sprite.h>
  19. #include <dbg.h>
  20. #include <dbgInt.h>
  21. #include <mach.h>
  22. #include <machConst.h>
  23. #include <proc.h>
  24. #include <vm.h>
  25. #include <vmMach.h>
  26. #include <machMon.h>
  27. #include <net.h>
  28. #include <netEther.h>
  29. #include <netInet.h>
  30. #include <dev.h>
  31. #include <sys.h>
  32. #include <sync.h>
  33. #include <main.h>
  34.  
  35. #ifdef KDBX
  36. #include <user/signal.h>
  37. #endif
  38.  
  39. extern Address vmStackBaseAddr;
  40. extern Address vmStackEndAddr;
  41. extern Address vmBlockCacheBaseAddr;
  42. extern Address vmBlockCacheEndAddr;
  43. extern Address vmBootEnd;
  44.  
  45. static unsigned sstepInst;            /* The instruction that was
  46.                          * replaced when we tried to
  47.                          * single step. */
  48. Boolean dbg_InDebugger = FALSE;            /* TRUE if are currently in
  49.                          * the debug command loop. */
  50. Boolean    dbg_BeingDebugged = FALSE;        /* TRUE if are under control
  51.                          * of kdbx.*/
  52. Boolean    dbg_Rs232Debug = FALSE;            /* TRUE if are using the RS232
  53.                          * line to debug, FALSE if are
  54.                          * using the network. */
  55. Boolean    dbg_UsingNetwork = FALSE;        /* TRUE if the debugger is
  56.                          * using the network interface*/
  57. static char requestBuffer[DBG_MAX_REQUEST_SIZE];/* Buffer to receive request
  58.                          * into. */
  59. static int    requestOffset;            /* Offset in buffer where next
  60.                          * bytes should be read from.*/
  61. static char replyBuffer[DBG_MAX_REPLY_SIZE + 2];/* Buffer to hold reply. */
  62. static int    replyOffset = 0;        /* Offset in buffer where next
  63.                          * bytes in reply should go. */
  64. static unsigned int    curMsgNum;        /* The current message that
  65.                          * is being processed. */
  66. int    dbgTraceLevel = 0;            /* The debugger tracing
  67.                          * level. */
  68.  
  69. /*
  70.  * Number of times to poll before timing out and resending (about 2 seconds).
  71.  */
  72. int    dbgTimeout = 15000;
  73.  
  74. /*
  75.  * Information about the latest packet received.
  76.  */
  77. Boolean            dbgGotPacket;    
  78. int            dbgPacketLength;
  79. Net_InetAddress        dbgMyIPAddr;
  80. Net_InetAddress        dbgSrcIPAddr;
  81. Net_InetAddress        dbgSrcPort;
  82. Net_EtherHdr        dbgEtherHdr;
  83. Net_ScatterGather    dbgGather;
  84. Net_Interface        *dbgInterPtr = (Net_Interface *) NIL;
  85.  
  86. /*
  87.  * Size of debugging packet header and data.
  88.  */
  89. #define    PACKET_HDR_SIZE (sizeof(Net_EtherHdr) + Dbg_PacketHdrSize() + 4 + 2)
  90. #define PACKET_DATA_SIZE (DBG_MAX_REPLY_SIZE - PACKET_HDR_SIZE)
  91.  
  92.  
  93. /*
  94.  * Strings which describe each of the opcodes that kdbx can send us.
  95.  */
  96. static char *opcodeNames[] = DBG_OPCODE_NAMES ;
  97.  
  98. /*
  99.  * Strings which describe the different exceptions that can occur.
  100. */
  101. static char *exceptionNames[] = DBG_EXCEPTION_NAMES;
  102.  
  103. /*
  104.  * Whether syslog should remain diverted on continue or not.
  105.  */
  106. static Boolean    syslogDiverted = FALSE;
  107.  
  108. /*
  109.  * Declare global variables.
  110.  */
  111. int        dbgTermReason;
  112. int        dbgInDebugger;
  113. int        dbgIntPending;
  114. Boolean        dbgPanic;
  115. Boolean        dbg_UsingSyslog = FALSE;
  116. Boolean        dbgCanUseSyslog = TRUE;
  117. int        dbgMaxStackAddr;
  118. #ifdef KDBX
  119. int        dbgSignal;
  120. static Boolean    useKdbx = FALSE;
  121. #endif
  122. /*
  123.  * Trap causes (same numbering as in ptrace.h).
  124.  */
  125. #define CAUSE_SINGLE    4
  126. #define CAUSE_BREAK    5
  127.  
  128. /*
  129.  * Trap instruction.
  130.  */
  131. #define SSTEP_INST    (MACH_SSTEP_VAL | 0xd)
  132.  
  133. /* 
  134.  * Forward declarations:
  135.  */
  136.  
  137. static char *    TranslateOpcode _ARGS_((int opcode));
  138. static char *    TranslateException _ARGS_((int exception));
  139. static Boolean    ReadRequest _ARGS_((Boolean timeout));
  140. static void    SendReply _ARGS_((int dataSize));
  141. static void    DebugToRegState _ARGS_((Mach_DebugState *debugPtr, 
  142.             Mach_RegState *regPtr));
  143. static void    RegStateToDebug _ARGS_((Mach_RegState *regPtr, 
  144.             Mach_DebugState *debugPtr)); 
  145.  
  146. #ifdef KDBX
  147. static int    sigMap[] = {
  148.     /* MACH_EXC_INT         */        SIGILL,
  149.     /* MACH_EXC_TLB_MOD     */        SIGSEGV,
  150.     /* MACH_EXC_TLB_LD_MISS     */        SIGSEGV, 
  151.     /* MACH_EXC_TLB_ST_MISS     */        SIGSEGV, 
  152.     /* MACH_EXC_ADDR_ERR_LD     */         SIGBUS,
  153.     /* MACH_EXC_ADDR_ERR_ST     */        SIGBUS,
  154.     /* MACH_EXC_BUS_ERR_IFETCH     */        SIGBUS,
  155.     /* MACH_EXC_BUS_ERR_LD_ST     */        SIGBUS,
  156.     /* MACH_EXC_SYSCALL     */        SIGSYS,
  157.     /* MACH_EXC_BREAK         */        SIGTRAP,
  158.     /* MACH_EXC_RES_INST     */        SIGILL,
  159.     /* MACH_EXC_COP_UNUSABLE     */        SIGILL, 
  160.     /* MACH_EXC_OVFLOW         */        SIGILL,
  161. };
  162.  
  163. #endif
  164.  
  165.  
  166. /*
  167.  * ----------------------------------------------------------------------------
  168.  *
  169.  * Dbg_InRange --
  170.  *
  171.  *     Return true if the given address is a valid kernel address and false
  172.  *     otherwise.
  173.  *
  174.  * Results:
  175.  *     True if the given address is a valid kernel address and false
  176.  *     otherwise.
  177.  *
  178.  * Side effects:
  179.  *     None.
  180.  *
  181.  * ----------------------------------------------------------------------------
  182.  */
  183. /*ARGSUSED*/
  184. Boolean Dbg_InRange(addr, numBytes, writeable) 
  185.     unsigned     int addr;     /* Beginning address to check. */
  186.     int        numBytes;     /* Number of bytes to check. */
  187.     Boolean    writeable;    /* TRUE => address must be writeable. */
  188. {
  189.     int            firstPage;
  190.     int            lastPage;
  191.  
  192.     firstPage = addr >> VMMACH_PAGE_SHIFT;
  193.     lastPage = (addr + numBytes - 1) >> VMMACH_PAGE_SHIFT;
  194.     if (firstPage != lastPage) {
  195.     Mach_MonPrintf("Dbg_InRange: Object spans pages\n");
  196.     return(FALSE);
  197.     }
  198.     return(VmMach_MakeDebugAccessible(addr));
  199. }
  200.  
  201.  
  202. /*
  203.  * ----------------------------------------------------------------------------
  204.  *
  205.  * TranslateOpcode --
  206.  *
  207.  *     Return the string which describes the given opcode.
  208.  *
  209.  * Results:
  210.  *     Pointer to the string which describes the given opcode.
  211.  *
  212.  * Side effects:
  213.  *     None.
  214.  *
  215.  * ----------------------------------------------------------------------------
  216.  */
  217. static char *
  218. TranslateOpcode(opcode)
  219.     int opcode;        /* The opcode which is to be translated. */
  220. {
  221.     int index;
  222.  
  223.     index = (int) opcode;
  224.     if (index < 0 || index >= sizeof(opcodeNames) / 4) {
  225.         index = 0;
  226.     }
  227.  
  228.     return(opcodeNames[index]);
  229. }
  230.  
  231.  
  232. /*
  233.  * ----------------------------------------------------------------------------
  234.  *
  235.  * TranslateException --
  236.  *
  237.  *     Return the string that describes the given exception.
  238.  *
  239.  * Results:
  240.  *     Pointer to string which describes the given exception.
  241.  *
  242.  * Side effects:
  243.  *     None.
  244.  *
  245.  * ----------------------------------------------------------------------------
  246.  */
  247. static char *
  248. TranslateException(exception)
  249.     int exception;        /* The exception which is to be translated. */
  250. {
  251.  
  252.     if (exception < 0 || exception > MACH_EXC_OVFLOW) {
  253.         return("Unknown");
  254.     } else {
  255.         return(exceptionNames[exception]);
  256.     }
  257. }
  258.  
  259.  
  260. /*
  261.  * ----------------------------------------------------------------------------
  262.  *
  263.  * Dbg_Init --
  264.  *
  265.  *     Initialize the debugger.
  266.  *
  267.  * Results:
  268.  *     None.
  269.  *
  270.  * Side effects:
  271.  *     Global variables are initialized.
  272.  *
  273.  * ----------------------------------------------------------------------------
  274.  */
  275. void
  276. Dbg_Init()
  277. {
  278. #ifdef KDBX
  279.     extern void DbgDbxInit();
  280. #endif
  281.     dbgInDebugger = 0;
  282.     dbgIntPending = 0;
  283.     dbgPanic = FALSE;
  284.     dbg_BeingDebugged = FALSE;
  285. #ifdef KDBX
  286.     DbgDbxInit();
  287. #endif
  288. }
  289.  
  290.  
  291.  
  292. /*
  293.  * ----------------------------------------------------------------------------
  294.  *
  295.  * Dbg_InputPacket --
  296.  *
  297.  *     See if the current packet is for us.
  298.  *
  299.  * Results:
  300.  *     None.
  301.  *
  302.  * Side effects:
  303.  *     dbgGotPacket is set to true if we got a packet that we liked.
  304.  *
  305.  * ----------------------------------------------------------------------------
  306.  */
  307. void
  308. Dbg_InputPacket(interPtr, packetPtr, packetLength)
  309.     Net_Interface    *interPtr;
  310.     Address        packetPtr;
  311.     int            packetLength;
  312. {
  313.     Net_EtherHdr    *etherHdrPtr;
  314.     Net_IPHeader    *ipPtr;
  315.     Address        dataPtr;
  316.     int            dataLength;
  317.  
  318.     if (interPtr->netType != NET_NETWORK_ETHER) {
  319.     return;
  320.     }
  321.     etherHdrPtr = (Net_EtherHdr *)packetPtr;
  322.  
  323.     if (dbgTraceLevel >= 5) {
  324.     if ((unsigned char)etherHdrPtr->destination.byte1 != 0xff) {
  325.         Mach_MonPrintf("Size=%d S: %x:%x:%x:%x:%x:%x D: %x:%x:%x:%x:%x:%x T=%x\n",
  326.             packetLength,
  327.             (unsigned char)etherHdrPtr->source.byte1,
  328.             (unsigned char)etherHdrPtr->source.byte2,
  329.             (unsigned char)etherHdrPtr->source.byte3,
  330.             (unsigned char)etherHdrPtr->source.byte4,
  331.             (unsigned char)etherHdrPtr->source.byte5,
  332.             (unsigned char)etherHdrPtr->source.byte6,
  333.             (unsigned char)etherHdrPtr->destination.byte1,
  334.             (unsigned char)etherHdrPtr->destination.byte2,
  335.             (unsigned char)etherHdrPtr->destination.byte3,
  336.             (unsigned char)etherHdrPtr->destination.byte4,
  337.             (unsigned char)etherHdrPtr->destination.byte5,
  338.             (unsigned char)etherHdrPtr->destination.byte6,
  339.             Net_NetToHostShort(etherHdrPtr->type));
  340.     }
  341.     }
  342.  
  343.     if (Net_NetToHostShort(etherHdrPtr->type) != NET_ETHER_IP) {
  344.     if (dbgTraceLevel >= 5) {
  345.         Mach_MonPrintf("Non-IP (Type=0x%x) ",
  346.             Net_NetToHostShort(etherHdrPtr->type));
  347.     }
  348.     return;
  349.     }
  350.     if (dbgGotPacket) {
  351.     if (dbgTraceLevel >= 4) {
  352.         Mach_MonPrintf("Dbg_InputPacket: already have a packet\n");
  353.     }
  354.     return;
  355.     }
  356.     if (dbgTraceLevel >= 4) {
  357.     Mach_MonPrintf("Validating packet\n");
  358.     }
  359.     { 
  360.     static char alignedBuffer[NET_ETHER_MAX_BYTES];
  361.         /*
  362.      * Make sure the packet starts on a 32-bit boundry so that we can
  363.      * use structures for describe the data.
  364.      */
  365.     if ( (unsigned int) (packetPtr + sizeof(Net_EtherHdr)) & 0x3 ) {
  366.           bcopy (packetPtr + sizeof(Net_EtherHdr), alignedBuffer,
  367.                 packetLength - sizeof(Net_EtherHdr));
  368.           packetPtr = alignedBuffer;
  369.     } else {
  370.           packetPtr = packetPtr + sizeof(Net_EtherHdr);
  371.     }
  372.  
  373.     if (Dbg_ValidatePacket(packetLength - sizeof(Net_EtherHdr),
  374.                    (Net_IPHeader *)(packetPtr),
  375.                    &dataLength, &dataPtr,
  376.                    &dbgMyIPAddr, &dbgSrcIPAddr, &dbgSrcPort)) {
  377.         if (dbgTraceLevel >= 4) {
  378.         Mach_MonPrintf("Got a packet: length=%d\n", dataLength);
  379.         }
  380.         bcopy((Address)etherHdrPtr, (Address)&dbgEtherHdr,
  381.             sizeof(Net_EtherHdr));
  382.         dbgGotPacket = TRUE;
  383.         bcopy(dataPtr, requestBuffer, dataLength);
  384. #ifdef KDBX
  385.         DbgDbxStoreRequest(dataLength, requestBuffer);
  386. #endif
  387.         /*
  388.          * Set the interface we are using. 
  389.          */
  390.         dbgInterPtr = interPtr;
  391.         return;
  392.     }
  393.     }
  394. }
  395.  
  396.  
  397. /*
  398.  * ----------------------------------------------------------------------------
  399.  *
  400.  * ReadRequest --
  401.  *
  402.  *     Read the next request from kdbx.
  403.  *
  404.  * Results:
  405.  *     None.
  406.  *
  407.  * Side effects:
  408.  *     TRUE if didn't time out.
  409.  *
  410.  * ----------------------------------------------------------------------------
  411.  */
  412. static Boolean
  413. ReadRequest(timeout)
  414.     Boolean    timeout;    /* TRUE if should timeout after waiting a 
  415.                  * while. */
  416. {
  417.     int            timeOutCounter;
  418.     Net_Interface    *interPtr;
  419.     int            i;
  420.  
  421.     dbgGotPacket = FALSE;
  422.     timeOutCounter = dbgTimeout;
  423.     do {
  424.     /*
  425.      * Listen on all the interfaces. The debugger is relatively
  426.      * stateless so its easiest to just listen on them all.
  427.      */
  428.     for (i = 0; ; i++) {
  429.         interPtr = Net_NextInterface(TRUE, &i);
  430.         if (interPtr == (Net_Interface *) NIL) {
  431.         break;
  432.         }
  433.         Net_RecvPoll(interPtr);
  434.         if (dbgGotPacket) {
  435.         break;
  436.         }
  437.     }
  438.     if (timeout) {
  439.         timeOutCounter--;
  440.     }
  441.     } while(!dbgGotPacket && timeOutCounter != 0);
  442.     if (dbgGotPacket) {
  443.     replyOffset = PACKET_HDR_SIZE;
  444.     requestOffset = 4;
  445.     curMsgNum = *(unsigned int *)(requestBuffer);
  446. #ifdef KDBX
  447.     if (curMsgNum > 0x40000000) {
  448.         useKdbx = FALSE;
  449.     } else {
  450.         useKdbx = TRUE;
  451.     }
  452. #endif
  453.     if (dbgTraceLevel >= 4) {
  454.         Mach_MonPrintf("MsgNum = %d\n", curMsgNum);
  455.     }
  456.     }
  457.  
  458.     return(dbgGotPacket);
  459. }
  460.  
  461. /*
  462.  * ----------------------------------------------------------------------------
  463.  *
  464.  * GetRequestBytes --
  465.  *
  466.  *     Get the next numBytes bytes from the current request.
  467.  *
  468.  * Results:
  469.  *     None.
  470.  *
  471.  * Side effects:
  472.  *     None.
  473.  *
  474.  * ----------------------------------------------------------------------------
  475.  */
  476. static void
  477. GetRequestBytes(numBytes, dest)
  478.     int        numBytes;
  479.     Address    dest;
  480. {
  481.     bcopy(requestBuffer + requestOffset, dest, numBytes);
  482.     requestOffset += numBytes;
  483. }
  484.  
  485.  
  486. /*
  487.  * ----------------------------------------------------------------------------
  488.  *
  489.  * PutReplyBytes --
  490.  *
  491.  *     Put the given bytes into the reply buffer.
  492.  *
  493.  * Results:
  494.  *     None.
  495.  *
  496.  * Side effects:
  497.  *     None.
  498.  *
  499.  * ----------------------------------------------------------------------------
  500.  */
  501. static void
  502. PutReplyBytes(numBytes, src)
  503.     int        numBytes;
  504.     Address    src;
  505. {
  506.     if (replyOffset + numBytes > DBG_MAX_REPLY_SIZE) {
  507.     Mach_MonPrintf("PutReplyBytes: Buffer overflow\n");
  508.     numBytes = DBG_MAX_REPLY_SIZE - replyOffset;
  509.     }
  510.     bcopy(src, &replyBuffer[replyOffset], numBytes);
  511.     replyOffset += numBytes;
  512. }
  513.  
  514.  
  515. /*
  516.  * ----------------------------------------------------------------------------
  517.  *
  518.  * SendReply --
  519.  *
  520.  *     Send a reply to kdbx.
  521.  *
  522.  * Results:
  523.  *     None.
  524.  *
  525.  * Side effects:
  526.  *     None.
  527.  *
  528.  * ----------------------------------------------------------------------------
  529.  */
  530. static void
  531. SendReply(dataSize)
  532.     int    dataSize;
  533. {
  534.     Net_EtherHdr        *etherHdrPtr;
  535.  
  536.     if (dbgTraceLevel >= 4) {
  537.     Mach_MonPrintf("Sending reply\n");
  538.     }
  539.  
  540.     etherHdrPtr = (Net_EtherHdr *) (replyBuffer+2);
  541.     etherHdrPtr->source = dbgEtherHdr.destination;
  542.     etherHdrPtr->destination = dbgEtherHdr.source;
  543.     etherHdrPtr->type = dbgEtherHdr.type;
  544.     dbgGather.bufAddr = replyBuffer + sizeof(Net_EtherHdr)+2;
  545.     dbgGather.length = replyOffset - sizeof(Net_EtherHdr)-2;
  546.     dbgGather.mutexPtr = (Sync_Semaphore *) NIL;
  547.     bcopy((char *)&curMsgNum,(char *)(replyBuffer + PACKET_HDR_SIZE - 4),4);
  548.     Dbg_FormatPacket(dbgMyIPAddr, dbgSrcIPAddr, dbgSrcPort,
  549.          replyOffset - sizeof(Net_EtherHdr) - Dbg_PacketHdrSize()-2,
  550.          replyBuffer + sizeof(Net_EtherHdr) + 2);
  551.     Net_RawOutput(dbgInterPtr, etherHdrPtr, &dbgGather, 1);
  552.     if (dbgTraceLevel >= 4) {
  553.     Mach_MonPrintf("Sent reply\n");
  554.     }
  555. }
  556.  
  557.  
  558. /*
  559.  * Should we sync the disks on entering the debugger?
  560.  */
  561.  
  562. Boolean dbgSyncDisks = TRUE;
  563.  
  564. extern Mach_DebugState    mach_DebugState;
  565.  
  566. /*
  567.  * Place where the TLB is dumped when the kernel enters the debugger.
  568.  */
  569. unsigned dbgTLB[VMMACH_NUM_TLB_ENTRIES][2];
  570.  
  571. static Mach_DebugState    *debugStatePtr;
  572.  
  573.  
  574. /*
  575.  * ----------------------------------------------------------------------------
  576.  *
  577.  * Dbg_Main --
  578.  *
  579.  *     The main debugger loop.  This will read commands from the network
  580.  *     and call the proper routine to execute them.
  581.  *
  582.  * Results:
  583.  *     None.
  584.  *
  585.  * Side effects:
  586.  *     None.
  587.  *
  588.  * ----------------------------------------------------------------------------
  589.  */
  590. unsigned
  591. Dbg_Main()
  592. {
  593.     unsigned    cause;
  594.     Boolean          done;        /* Boolean to tell us whether to leave
  595.                      * the main debugger loop */
  596.     Dbg_Opcode          opcode;            /* The operation that was requested */
  597.                     /* Process table entry that we switched
  598.                      * stacks to. */
  599.     Proc_ControlBlock    *procPtr = (Proc_ControlBlock *) NIL;
  600.     Boolean        atInterruptLevel;/* TRUE if we were entered from an
  601.                       * interrupt handler. */
  602.     extern int Mach_SwitchPoint();
  603. #ifdef NOTDEF
  604. /*
  605.  * This code causes machines to "pop out" of the debugger.
  606.  */
  607.     if (!dbg_BeingDebugged && dbgSyncDisks) {
  608.     /*
  609.      * Try to sync the disks if we aren't at interrupt level.  If we
  610.      * are don't bother because we'll just hang waiting for interrupts.
  611.      * Of course I could force interrupts to be enabled but I'm not sure
  612.      * if that's a great idea.
  613.      */
  614.     if (mach_NumDisableIntrsPtr[0] == 0 &&
  615.         !mach_AtInterruptLevel) {
  616.         Mach_EnableIntr();
  617.         Sys_SyncDisks(MACH_OTHER_TRAP_TYPE);
  618.         Mach_DisableIntr();
  619.     }
  620.     }
  621. #endif NOTDEF
  622.  
  623.     dbg_InDebugger = TRUE;
  624.  
  625.     debugStatePtr = &mach_DebugState;
  626.  
  627.     if (dbgTraceLevel >= 1) {
  628.     unsigned int    *sp;
  629.     extern int etext;
  630.     
  631.     Mach_MonPrintf("\nCause=%x SR=%x excPC=%x SP=%x BVA=%x\n", 
  632.                mach_DebugState.causeReg, mach_DebugState.statusReg, 
  633.                mach_DebugState.excPC, mach_DebugState.regs[SP],
  634.                mach_DebugState.badVaddr);
  635.     Mach_MonPrintf("Stack:\n");
  636.     for (sp = (unsigned *)mach_DebugState.regs[SP]; 
  637.          sp < (unsigned *)0x80030000; 
  638.          sp++) {
  639.         if ((*sp < (unsigned int)&etext) && (*sp >= (unsigned)0x80030000)) {
  640.         Mach_MonPrintf("%x\n", *sp);
  641.         }
  642.     }
  643.     }
  644.  
  645.     atInterruptLevel = mach_AtInterruptLevel;
  646.     mach_AtInterruptLevel = TRUE;
  647.  
  648.     /*
  649.      * Force system log output to the console.
  650.      */
  651.     if (!syslogDiverted) {
  652.     Dev_SyslogDebug(TRUE);
  653.     }
  654.  
  655.     /*
  656.      * We want to inform the user what caused the problem.  However we only
  657.      * tell him if: 1) we are debugging the debugger; 2) we are not under 
  658.      * debugger control (i.e. we don't want to inform the user on every trace 
  659.      * trap), 3) we got something besides a trace trap or a breakpoint trap
  660.      * exception.
  661.      */
  662.     cause = (mach_DebugState.causeReg & MACH_CR_EXC_CODE) >> 
  663.                         MACH_CR_EXC_CODE_SHIFT;
  664.     if (dbgPanic) {
  665.     dbgPanic = FALSE;
  666.     mach_DebugState.excPC = mach_DebugState.regs[RA];
  667.     }
  668.  
  669.     if (dbgTraceLevel >= 1 || !dbg_BeingDebugged || 
  670.         cause != MACH_EXC_BREAK) {
  671.     (void)Dev_VidEnable(TRUE); /* unblank the screen */
  672.     printf("Entering debugger with a %s exception at PC 0x%x\r\n",
  673.            TranslateException((int)cause),
  674.            mach_DebugState.excPC);
  675.     }
  676. #ifdef KDBX
  677.     if ((cause >= 0) && (cause < MACH_EXC_MAX)) {
  678.     dbgSignal = sigMap[cause];
  679.     } else {
  680.     dbgSignal = SIGILL;
  681.     }
  682. #endif
  683.     if (cause == MACH_EXC_BREAK) {
  684.     unsigned        *pc;
  685.  
  686.     if (mach_DebugState.causeReg & MACH_CR_BR_DELAY) {
  687.         pc = (unsigned *)(mach_DebugState.excPC + 4);
  688.     } else {
  689.         pc = (unsigned *)mach_DebugState.excPC;
  690.     }
  691.     if (dbgTraceLevel >= 1) {
  692.         Mach_MonPrintf("break inst: %x\n", *pc);
  693.     }
  694.     if ((*pc & MACH_BREAK_CODE_FIELD) == MACH_SSTEP_VAL) {
  695.         if (dbgTraceLevel >= 1) {
  696.         Mach_MonPrintf("sstep\n");
  697.         }
  698.         mach_DebugState.trapCause = CAUSE_SINGLE;
  699.         if (dbgTraceLevel >= 1) {
  700.         Mach_MonPrintf("sstep (%x) = %x\n", pc, sstepInst);
  701.         }
  702.         Mach_FlushCode((Address)pc, 4);
  703.         *pc = sstepInst;
  704.         Mach_EmptyWriteBuffer();
  705.     } else {
  706.         mach_DebugState.trapCause = CAUSE_BREAK;
  707.     }
  708.     }
  709.  
  710.     dbg_UsingNetwork = TRUE;
  711.  
  712.     if (dbg_BeingDebugged) {
  713.         unsigned        char    ch;
  714.     int    timeout = 5;
  715.         ch = 0;
  716. #ifdef KDBX
  717.     if (useKdbx) {
  718.         Dbg_DbxMain();
  719.         goto there;
  720.     }
  721. #endif
  722.         PutReplyBytes(1, (Address)&ch);
  723.         SendReply();
  724.         do {
  725.             if (ReadRequest(TRUE)) {
  726.                 GetRequestBytes(4, (Address)&opcode);
  727.         if (opcode != DBG_CONTINUE) {
  728.             break;
  729.         } else {
  730.             PutReplyBytes(4, (Address) &opcode);
  731.             SendReply();
  732.             continue;
  733.         }
  734.             }
  735.             /*
  736.              * We can only timeout if we are using network debugging.
  737.              */
  738.         Net_RawOutput(dbgInterPtr, (Address) replyBuffer, 
  739.             &dbgGather, 1);
  740.             if (dbgTraceLevel >= 5) {
  741.                 Mach_MonPrintf("DBG: Timeout\n");
  742.             }
  743.             Mach_MonPrintf("TI ");
  744.         } while (timeout-- > 0);
  745.     } else {
  746.         (void) ReadRequest(FALSE);
  747. #ifdef KDBX
  748.     if (useKdbx) {
  749.         Dbg_DbxMain();
  750.         goto there;
  751.     }
  752. #endif
  753.         GetRequestBytes(4, (Address)&opcode);
  754.     }
  755.  
  756.     Vm_MachDumpTLB(dbgTLB);
  757.  
  758.     done = FALSE;
  759.     while (!done) {
  760.     if (dbgTraceLevel >= 2) {
  761.         Mach_MonPrintf("Request: (%d) %s\n", opcode, TranslateOpcode(opcode));
  762.     }
  763.     switch (opcode) {
  764.  
  765.         /*
  766.          * The client wants to read some data from us ...
  767.          */
  768.  
  769.         case DBG_GET_STOP_INFO: {
  770.         StopInfo    stopInfo;
  771.         stopInfo.codeStart = (int)mach_CodeStart;
  772.         if (procPtr != (Proc_ControlBlock *) NIL &&
  773.             procPtr->machStatePtr != (Mach_State *)NIL) {
  774.             stopInfo.regs = procPtr->machStatePtr->switchRegState;
  775.             /*
  776.              * The pc isn't stored in switchRegState, but we know
  777.              * that we had to be in Mach_ContextSwitch.  Also,
  778.              * when the context switch is done the status register
  779.              * and a magic number are pushed on the stack. We
  780.              * need to adjust the sp so that the debugger doesn't
  781.              * get confused by them. 
  782.              */
  783.             stopInfo.regs.pc = (Address) 
  784.                     ((int) Mach_ContextSwitch + 16);
  785.             stopInfo.regs.regs[SP] += 8;
  786.         } else {
  787.             DebugToRegState(&mach_DebugState, &stopInfo.regs);
  788.         }
  789.         stopInfo.trapType = cause;
  790.         PutReplyBytes(sizeof(stopInfo), (Address)&stopInfo);
  791.         SendReply();
  792.         break;
  793.         }
  794.         case DBG_READ_ALL_REGS: {
  795.         Mach_RegState    regState;
  796.         if (procPtr != (Proc_ControlBlock *) NIL &&
  797.             procPtr->machStatePtr != (Mach_State *)NIL) {
  798.             regState = procPtr->machStatePtr->switchRegState;
  799.             regState.pc = (Address) (Mach_SwitchPoint);
  800.             regState.pc = (Address) 
  801.                 ((int) Mach_ContextSwitch + 16);
  802.             regState.regs[SP] += 8;
  803.         } else {
  804.             DebugToRegState(&mach_DebugState, ®State);
  805.         }
  806.         PutReplyBytes(sizeof(regState), (Address) ®State);
  807.         SendReply();
  808.         }
  809.         case DBG_GET_DUMP_BOUNDS: {
  810.         Dbg_DumpBounds bounds;
  811.         extern unsigned int end;
  812.         bounds.pageSize = vm_PageSize;
  813.         bounds.stackSize = mach_KernStackSize;
  814.         bounds.kernelCodeStart = (unsigned int) mach_KernStart;
  815.         bounds.kernelCodeSize  = 
  816.             (unsigned int) (vmBootEnd - mach_KernStart);
  817.         bounds.kernelDataStart    = VMMACH_VIRT_CACHED_START;
  818.         bounds.kernelDataSize    = (unsigned int) 
  819.                 (vmMemEnd - VMMACH_VIRT_CACHED_START);
  820.         bounds.kernelStacksStart = (unsigned int)vmStackBaseAddr;
  821.         bounds.kernelStacksSize = (unsigned int) 
  822.                 (vmStackEndAddr - vmStackBaseAddr);
  823.         bounds.fileCacheStart    = (unsigned int)vmBlockCacheBaseAddr;
  824.         bounds.fileCacheSize    = (unsigned int) (vmBlockCacheEndAddr - 
  825.                         vmBlockCacheBaseAddr);
  826.  
  827.         PutReplyBytes(sizeof(bounds), (char *)&bounds);
  828.         SendReply();
  829.         break;
  830.         }
  831.         case DBG_GET_VERSION_STRING: {
  832.         char    *version;
  833.  
  834.         version = SpriteVersion();
  835.         PutReplyBytes(strlen(version) + 1, version);
  836.         SendReply();
  837.         break;
  838.         }
  839.         case DBG_INST_READ:
  840.         case DBG_DATA_READ: {
  841.         Dbg_ReadMem    readMem;
  842.         int        status;
  843.  
  844.         GetRequestBytes(sizeof(readMem), (Address) &readMem); 
  845.         if (dbgTraceLevel >= 2) {
  846.             Mach_MonPrintf("Addr=%x Numbytes=%d ",
  847.                 readMem.address, readMem.numBytes);
  848.         }
  849.         if (Dbg_InRange(readMem.address, readMem.numBytes, FALSE)) {
  850.             status = 1;
  851.             PutReplyBytes(sizeof(status), (Address)&status);
  852.             PutReplyBytes(readMem.numBytes, (Address)readMem.address);
  853.         } else {
  854.             if (dbgTraceLevel >= 2) {
  855.             Mach_MonPrintf("FAILURE ");
  856.             }
  857.             status = 0;
  858.             PutReplyBytes(sizeof(status), (Address)&status);
  859.         }
  860.         SendReply();
  861.         break;
  862.         }
  863.         case DBG_SET_PID: {
  864.         Proc_PID    pid;
  865.  
  866.         GetRequestBytes(sizeof(pid), (Address) &pid);
  867.          {
  868.             int    dummy;
  869.  
  870.             PutReplyBytes(4, (Address) &dummy);
  871.             SendReply();
  872.         }
  873.         if (dbgTraceLevel >= 2) {
  874.             Mach_MonPrintf("pid %x ", pid);
  875.         }
  876.         if (pid == 0) {
  877.             procPtr = (Proc_ControlBlock *) NIL;
  878.         } else {
  879.             procPtr = Proc_GetPCB(pid);
  880.             if (procPtr == (Proc_ControlBlock *) NIL ||
  881.                 procPtr == (Proc_ControlBlock *) 0 ||
  882.             procPtr->state == PROC_UNUSED ||
  883.                 procPtr->state == PROC_DEAD ||
  884.             procPtr->state == PROC_NEW) {
  885.             Mach_MonPrintf("Can't backtrace stack for process %x\n",
  886.                     pid);
  887.             procPtr = (Proc_ControlBlock *) NIL;
  888.             }
  889.         }
  890.         break;
  891.         }
  892.         case DBG_REBOOT: {
  893.         int    stringLength;
  894.         char    rebootString[100];
  895.         /*
  896.          * For a reboot command first read the size of the string and
  897.          * then the string itself.
  898.          */
  899.         GetRequestBytes(sizeof(int), (Address)&stringLength);
  900.         if (stringLength != 0) {
  901.             GetRequestBytes(stringLength, (Address)rebootString);
  902.         }
  903.         rebootString[stringLength] = '\0';
  904.          {
  905.             int    dummy;
  906.  
  907.             PutReplyBytes(4, (Address) &dummy);
  908.             SendReply();
  909.         }
  910.         Mach_MonReboot(rebootString);
  911.         }
  912.         case DBG_INST_WRITE:
  913.         case DBG_DATA_WRITE: {
  914.         Dbg_WriteMem        writeMem;
  915.         unsigned    char    ch;
  916.         /*
  917.          * For an instruction or a data write we first have to find out 
  918.          * which address to write to and how many bytes to write.  Next
  919.          * we have to make sure that the address is valid.  If it is
  920.          * then we read the data and write it to the given address.  If
  921.          * not we just report an error to kdbx.
  922.          */
  923.         GetRequestBytes(2 * sizeof(int), (Address) &writeMem);
  924.         if (dbgTraceLevel >= 2) {
  925.             Mach_MonPrintf("Addr=%x Numbytes=%d ",
  926.                 writeMem.address, writeMem.numBytes);
  927.         }
  928.         if (Dbg_InRange((unsigned int) writeMem.address,
  929.                 writeMem.numBytes, opcode == DBG_DATA_WRITE)) {
  930.             GetRequestBytes(writeMem.numBytes,
  931.                     (Address) writeMem.address);
  932.             if (opcode == DBG_INST_WRITE) {
  933.             Mach_FlushCode((Address)writeMem.address, 
  934.                 writeMem.numBytes);
  935.             Mach_EmptyWriteBuffer();
  936.             }
  937.             ch = 1;
  938.         } else {
  939.             char    buf[100];
  940.  
  941.             if (dbgTraceLevel >= 2) {
  942.             Mach_MonPrintf("FAILURE ");
  943.             }
  944.             GetRequestBytes(writeMem.numBytes, buf);
  945.             ch = 0;
  946.         }
  947.         PutReplyBytes(1, (char *) &ch);
  948.         SendReply();
  949.  
  950.         break;
  951.         }
  952.         case DBG_WRITE_REG: {                
  953.         Mach_RegState    regState;
  954.         Dbg_WriteReg    writeReg;
  955.  
  956.         /*
  957.          * First find out which register is being written and
  958.          * then read the value.
  959.          */
  960.         GetRequestBytes(sizeof(writeReg), (Address)&writeReg);
  961.          {
  962.             int    dummy;
  963.  
  964.             PutReplyBytes(4, (Address) &dummy);
  965.             SendReply();
  966.         }
  967.         if (dbgTraceLevel >= 2) {
  968.             Mach_MonPrintf("register %d data %x ", writeReg.regNum, 
  969.                 writeReg.regVal);
  970.         }
  971.         if (procPtr != (Proc_ControlBlock *) NIL &&
  972.             procPtr->machStatePtr != (Mach_State *)NIL) {
  973.             ((int *) 
  974.             &procPtr->machStatePtr->switchRegState)[(writeReg.regNum)] 
  975.             = writeReg.regVal;
  976.         } else {
  977.             DebugToRegState(&mach_DebugState, ®State);
  978.             ((int *) ®State)[(writeReg.regNum)] = writeReg.regVal;
  979.             RegStateToDebug(®State, &mach_DebugState);
  980.         }
  981.         }
  982.         case DBG_DIVERT_SYSLOG: 
  983.         GetRequestBytes(sizeof(Boolean), (Address)&syslogDiverted);
  984.          {
  985.             int    dummy;
  986.  
  987.             PutReplyBytes(4, (Address) &dummy);
  988.             SendReply();
  989.         }
  990.         break;
  991.         case DBG_BEGIN_CALL: {
  992.         /*
  993.          * We are beginning a call command.  Fix up the stack
  994.          * so that we will be able to continue.  We will put
  995.          * it back when we are done.
  996.          */
  997.         int    dummy;
  998.         if (dbgCanUseSyslog) {
  999.             dbg_UsingSyslog = TRUE;
  1000.         }
  1001.  
  1002.         PutReplyBytes(4, (Address) &dummy);
  1003.         SendReply();
  1004.  
  1005.         break;
  1006.         }
  1007.         case DBG_END_CALL: {
  1008.         char    *buffer;
  1009.         int    *firstIndexPtr;
  1010.         int    *lastIndexPtr;
  1011.         int    bufSize;
  1012.         int    length;
  1013.         /*
  1014.          * Dump the syslog buffer.
  1015.          */
  1016.         Dev_SyslogReturnBuffer(&buffer, &firstIndexPtr,
  1017.                        &lastIndexPtr, &bufSize);
  1018.         if (*firstIndexPtr == -1) {
  1019.             length = 0;
  1020.             PutReplyBytes(4, (Address) &length);
  1021.             dbg_UsingSyslog = FALSE;
  1022.         } else if (*firstIndexPtr <= *lastIndexPtr) {
  1023.             length = *lastIndexPtr - *firstIndexPtr + 1;
  1024.             if (length + 4 > PACKET_DATA_SIZE) {
  1025.             length = PACKET_DATA_SIZE - 4;
  1026.             }
  1027.             PutReplyBytes(4, (Address) &length);
  1028.             PutReplyBytes(length,
  1029.                   (Address)&buffer[*firstIndexPtr]);
  1030.             *firstIndexPtr += length;
  1031.             if (*firstIndexPtr > *lastIndexPtr) {
  1032.             *firstIndexPtr = *lastIndexPtr = -1;
  1033.             }
  1034.         } else {
  1035.             length = bufSize - *firstIndexPtr;
  1036.             if (length + 4 > PACKET_DATA_SIZE) {
  1037.             length = PACKET_DATA_SIZE - 4;
  1038.             }
  1039.             PutReplyBytes(4, (Address) &length);
  1040.             PutReplyBytes(length,
  1041.                   (Address)buffer[*firstIndexPtr]);
  1042.             *firstIndexPtr += length;
  1043.             if (*firstIndexPtr == bufSize) {
  1044.             *firstIndexPtr = 0;
  1045.             }
  1046.         }
  1047.         SendReply();
  1048.         break;
  1049.         }
  1050.         case DBG_CALL_FUNCTION: {
  1051.         Dbg_CallFunc        callFunc;
  1052.         int            returnVal;
  1053.         static int        argBuf[128];
  1054.         GetRequestBytes(2 * sizeof(int), (Address) &callFunc);
  1055.         if (dbgTraceLevel >= 2) {
  1056.             Mach_MonPrintf("Addr=%x Numbytes=%d ",
  1057.                 callFunc.address, callFunc.numBytes);
  1058.         }
  1059.         if ((callFunc.numBytes >= 0 && callFunc.numBytes < 128) &&
  1060.              Dbg_InRange((unsigned int) callFunc.address,4,FALSE)) {
  1061.             GetRequestBytes(callFunc.numBytes,(Address) argBuf);
  1062.             returnVal = (* ((int (*)()) callFunc.address))(argBuf[0],
  1063.             argBuf[1],argBuf[2],argBuf[3],argBuf[4],argBuf[5],argBuf[6],
  1064.             argBuf[7],argBuf[8],argBuf[9]);
  1065.         } else {
  1066.  
  1067.             if (dbgTraceLevel >= 2) {
  1068.             Mach_MonPrintf("FAILURE ");
  1069.             }
  1070.             GetRequestBytes(callFunc.numBytes,(Address)argBuf);
  1071.             returnVal = -1;
  1072.         }
  1073.         PutReplyBytes(4, (char *) &returnVal);
  1074.         SendReply();
  1075.  
  1076.         break;
  1077.         }
  1078.         case DBG_CONTINUE: {
  1079.         /*
  1080.          * The client wants to continue execution.
  1081.          */
  1082.         int    foo;
  1083.         GetRequestBytes(sizeof(int), 
  1084.                 (Address) &foo);
  1085.         if (dbgTraceLevel >= 2) {
  1086.             Mach_MonPrintf("Continuing from pc %x ",debugStatePtr->excPC);
  1087.         }
  1088.         {
  1089.             int    dummy;
  1090.  
  1091.             PutReplyBytes(4, (Address) &dummy);
  1092.             SendReply();
  1093.         }
  1094.  
  1095.         dbg_BeingDebugged = TRUE;
  1096.         done = TRUE;
  1097.         break;
  1098.         }
  1099.         case DBG_SINGLESTEP: {
  1100.         /*
  1101.          * The client wants to single step.
  1102.          */
  1103.         unsigned        *pc;
  1104.         int            status;
  1105.         int            dummy;
  1106.  
  1107.         GetRequestBytes(sizeof(int),  (Address) &dummy);
  1108.         pc = DbgGetDestPC((Address)(debugStatePtr->excPC));
  1109.         if (dbgTraceLevel >= 1) {
  1110.             Mach_MonPrintf("Single-step PC=%x\n", pc);
  1111.         }
  1112.         if (!Dbg_InRange((unsigned int)pc, 4, TRUE)) {
  1113.             Mach_MonPrintf("Bad SSTEP PC\n");
  1114.             status = 0;
  1115.         } else {
  1116.             sstepInst = *pc;
  1117.             Mach_FlushCode((Address)pc, 4);
  1118.             *pc = SSTEP_INST;
  1119.             Mach_EmptyWriteBuffer();
  1120.             dbg_BeingDebugged = TRUE;
  1121.             done = TRUE;
  1122.             status = 1;
  1123.         }
  1124.         PutReplyBytes(sizeof(status), (Address) &status);
  1125.         SendReply();
  1126.         break;
  1127.         }
  1128.         case DBG_DETACH:
  1129.         /*
  1130.          * The debugger has terminated and wants to let us go about our
  1131.          * business.
  1132.          */
  1133.         if (dbgTraceLevel >= 2) {
  1134.             Mach_MonPrintf("Detaching at pc %x ", debugStatePtr->excPC);
  1135.         }
  1136.             {
  1137.             int    dummy;
  1138.  
  1139.             PutReplyBytes(4, (Address) &dummy);
  1140.             SendReply();
  1141.         }
  1142.  
  1143.         dbg_BeingDebugged = FALSE;
  1144.         done = TRUE;
  1145.         printf("Sprite is now detached from the debugger\r\n");
  1146.         break;
  1147.         case DBG_UNKNOWN:
  1148.         Mach_MonPrintf("debugger: unrecognized request\n");
  1149.         break;
  1150.     }
  1151.     if (dbgTraceLevel >= 2) {
  1152.         Mach_MonPrintf("\r\n");
  1153.     }
  1154.     if (!done) {
  1155.         (void)ReadRequest(FALSE);
  1156.         GetRequestBytes(4, (Address)&opcode);
  1157.     }
  1158.     }
  1159.  
  1160. #ifdef KDBX
  1161. there:
  1162. #endif
  1163.     /*
  1164.      * Don't force system log output to the console.
  1165.      */
  1166.     if (!syslogDiverted) {
  1167.     Dev_SyslogDebug(FALSE);
  1168.     }
  1169.  
  1170.     if (dbgTraceLevel >= 1) {
  1171.     Mach_MonPrintf("Returning to %x: %x\n", debugStatePtr->excPC, 
  1172.                 *(unsigned *)debugStatePtr->excPC);
  1173.     }
  1174.  
  1175.     mach_AtInterruptLevel = atInterruptLevel;
  1176.     dbg_UsingNetwork = FALSE;
  1177.     /*
  1178.      * Flush out the old TLB mapping.
  1179.      */
  1180.     VmMachWriteIndexedTLB(0, 0, 0);
  1181.  
  1182.     dbg_InDebugger = FALSE;
  1183.  
  1184.     return(debugStatePtr->excPC);
  1185. }
  1186.  
  1187. /*
  1188.  *----------------------------------------------------------------------
  1189.  *
  1190.  * DebugToRegState --
  1191.  *
  1192.  *    Converts a Mach_DebugState to Mach_RegState.
  1193.  *
  1194.  * Results:
  1195.  *    None.
  1196.  *
  1197.  * Side effects:
  1198.  *    None.
  1199.  *
  1200.  *----------------------------------------------------------------------
  1201.  */
  1202. static void
  1203. DebugToRegState(debugPtr, regPtr)
  1204.     Mach_DebugState    *debugPtr;
  1205.     Mach_RegState    *regPtr;
  1206. {
  1207.     regPtr->pc = (Address) debugPtr->excPC;
  1208.     bcopy((char *) debugPtr->regs, (char *) regPtr->regs, 
  1209.     MACH_NUM_GPRS * sizeof(int));
  1210.     bcopy((char *) debugPtr->fpRegs, (char *) regPtr->fpRegs, 
  1211.     MACH_NUM_FPRS * sizeof(int));
  1212.     regPtr->fpStatusReg = debugPtr->fpCSR;
  1213.     regPtr->mfhi = debugPtr->multHi;
  1214.     regPtr->mflo = debugPtr->multLo;
  1215. }
  1216.  
  1217. /*
  1218.  *----------------------------------------------------------------------
  1219.  *
  1220.  * RegStateToDebug --
  1221.  *
  1222.  *    Converts a Mach_RegState to Mach_DebugState.
  1223.  *
  1224.  * Results:
  1225.  *    None.
  1226.  *
  1227.  * Side effects:
  1228.  *    None.
  1229.  *
  1230.  *----------------------------------------------------------------------
  1231.  */
  1232.  
  1233. static void
  1234. RegStateToDebug(regPtr, debugPtr)
  1235.     Mach_RegState    *regPtr;
  1236.     Mach_DebugState    *debugPtr;
  1237. {
  1238.     debugPtr->excPC = (unsigned) regPtr->pc;
  1239.     bcopy((char *) regPtr->regs, (char *) debugPtr->regs, 
  1240.     MACH_NUM_GPRS * sizeof(int));
  1241.     bcopy((char *) regPtr->fpRegs, (char *) debugPtr->fpRegs, 
  1242.     MACH_NUM_FPRS * sizeof(int));
  1243.     debugPtr->fpCSR = regPtr->fpStatusReg;
  1244.     debugPtr->multHi = regPtr->mfhi;
  1245.     debugPtr->multLo = regPtr->mflo;
  1246. }
  1247.  
  1248.